package org.infodavid.common.ejb;

import java.util.List;

import javax.ejb.Local;
import javax.ejb.PrePassivate;
import javax.ejb.Remote;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;

import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.Index;
import org.hibernate.annotations.IndexColumn;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.Persister;
import org.hibernate.annotations.Target;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;

import org.infodavid.common.ejb.components.EMailComponent;
import org.infodavid.common.ejb.components.GenericPropertyComponent;
import org.infodavid.common.ejb.components.ImageDataComponent;
import org.infodavid.common.ejb.components.LocationComponent;
import org.infodavid.common.ejb.components.PhoneComponent;
import org.infodavid.common.ejb.components.UriComponent;
import org.infodavid.common.impl.model.PersonImpl;
import org.infodavid.common.model.IGenericPropertiesMap;
import org.infodavid.common.model.IGenericProperty;
import org.infodavid.common.model.IImageData;
import org.infodavid.common.model.IPerson;
import org.infodavid.common.model.components.IEMail;
import org.infodavid.common.model.components.ILocation;
import org.infodavid.common.model.components.IPhone;
import org.infodavid.common.model.components.IUri;
import org.infodavid.common.model.impl.persisters.VersionSafeSingleTableEntityPersister;
import org.infodavid.common.persistence.INamed;
import org.infodavid.common.persistence.PersonDataService;

/**
 * The Class PersonBean.
 */
@Entity(name = "IPerson")
@org.hibernate.annotations.Entity(dynamicUpdate = true, selectBeforeUpdate = true, dynamicInsert = true, optimisticLock = OptimisticLockType.VERSION)
@Persister(impl = VersionSafeSingleTableEntityPersister.class)
@Table(name = "PERSONS")
@NamedQueries(value = {
    @NamedQuery(name = PersonDataService.QUERY_FIND_COUNT, query = "select count(d." + IPerson.KEY
        + ") from IPerson d"),
    @NamedQuery(name = PersonDataService.QUERY_FIND, query = "select d from IPerson d"),
    @NamedQuery(name = PersonDataService.QUERY_FIND_ACTIVE_COUNT, query = "select count(d."
        + IPerson.KEY + ") from IPerson d where d.archived = 0"),
    @NamedQuery(name = PersonDataService.QUERY_FIND_ACTIVE, query = "select d from IPerson d where d.archived = 0"),
    @NamedQuery(name = PersonDataService.QUERY_FIND_BY_NAME, query = "select d from IPerson d where d.archived = 0 and :"
        + IPerson.NAME + " is null or d." + IPerson.NAME + " like :" + IPerson.NAME),
    @NamedQuery(name = PersonDataService.QUERY_FIND_BY_NAME_COUNT, query = "select count(d."
        + IPerson.KEY + ") from IPerson d where d.archived = 0 and :" + IPerson.NAME
        + " is null or d." + IPerson.NAME + " like :" + IPerson.NAME),
    @NamedQuery(name = PersonDataService.QUERY_FIND_BY_CREATION_DATE, query = "select d from IPerson d where d.archived = 0 and d."
        + IPerson.CREATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = PersonDataService.QUERY_FIND_BY_CREATION_DATE_COUNT, query = "select count(d."
        + IPerson.KEY
        + ") from IPerson d where d.archived = 0 and d."
        + IPerson.CREATION_DATE
        + " between :date1 and :date2"),
    @NamedQuery(name = PersonDataService.QUERY_FIND_BY_MODIFICATION_DATE, query = "select d from IPerson d where d.archived = 0 and d."
        + IPerson.MODIFICATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = PersonDataService.QUERY_FIND_BY_MODIFICATION_DATE_COUNT, query = "select count(d."
        + IPerson.KEY
        + ") from IPerson d where d.archived = 0 and d."
        + IPerson.MODIFICATION_DATE
        + " between :date1 and :date2")
})
@Local(value = IPerson.class)
@Remote(value = IPersonRemote.class)
public class PersonBean extends PersonImpl {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 1660345027625851664L;

	/**
	 * The Constructor.
	 * @throws Exception the exception
	 */
	protected PersonBean() throws Exception {
		super();
	}

	/**
	 * The Constructor.
	 * @param keyArg the key arg
	 * @throws Exception the exception
	 */
	protected PersonBean(final Long keyArg) throws Exception {
		super(keyArg);
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.PersonImpl#init()
	 */
	@Override
	@PrePassivate
	public void init() throws Exception {
		super.init();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getCreationDate()
	 */
	@Override
	@Column(name = CREATION_DATE, nullable = false, updatable = false)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	@Index(name = "IDX_PERSONS_CREATIONDATE")
	public DateTime getCreationDate() {
		return super.getCreationDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getModificationDate()
	 */
	@Override
	@Version
	@Column(name = MODIFICATION_DATE, nullable = false)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	public DateTime getModificationDate() {
		return super.getModificationDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getKey()
	 */
	@Override
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = ID, nullable = false)
	public Long getKey() {
		return super.getKey();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#isArchived()
	 */
	@Override
	@Column(name = ARCHIVED, nullable = false)
	@Index(name = "IDX_PERSONS_ARCHIVED")
	public boolean isArchived() {
		return super.isArchived();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getName()
	 */
	@Override
	@Column(name = NAME, length = 96, nullable = false, unique = false)
	@Index(name = "IDX_PERSONS_NAME")
	public String getName() {
		return super.getName();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getComment()
	 */
	@Override
	@Column(name = COMMENT, length = 1024, nullable = true)
	public String getComment() {
		return super.getComment();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.PersonImpl#getBirthDate()
	 */
	@Override
	@Column(name = BIRTH_DATE, nullable = true)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	public DateTime getBirthDate() {
		return super.getBirthDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.PersonImpl#getDeathDate()
	 */
	@Override
	@Column(name = DEATH_DATE, nullable = true)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	@Index(name = "IDX_PERSONS_DEATHDATE")
	public DateTime getDeathDate() {
		return super.getDeathDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.PersonImpl#getFirstname()
	 */
	@Override
	@Column(name = FIRST_NAME, nullable = true, length = 64)
	public String getFirstName() {
		return super.getFirstName();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.PersonImpl#getTitle()
	 */
	@Override
	@Column(name = TITLE, nullable = true, length = 32)
	@Enumerated(EnumType.STRING)
	public EPersonTitle getTitle() {
		return super.getTitle();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getIdentity()
	 */
	@Override
	@Column(name = IDENTITY, nullable = true, length = 128)
	@Index(name = "IDX_PERSONS_IDENTITY")
	public String getIdentity() {
		return super.getIdentity();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.PersonImpl#getNationality()
	 */
	@Override
	@Column(name = NATIONALITY, nullable = true, length = 3)
	public String getNationality() {
		return super.getNationality();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.PersonImpl#getAge()
	 */
	@Override
	@Transient
	public byte getAge() {
		return super.getAge();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getEmails()
	 */
	@Override
	@ElementCollection(fetch = FetchType.LAZY, targetClass = EMailComponent.class)
	@CollectionTable(name = "PERSONS_EMAILS", joinColumns = @JoinColumn(name = ID, nullable = false), uniqueConstraints = @UniqueConstraint(name = "UC_PERSONS_EMAILS", columnNames = {
	    "value", ID
	}))
	@IndexColumn(name = "priority", base = 0)
	@ForeignKey(name = "FK_PERSONS_EMAILS")
	public List<IEMail> getEmails() {
		return super.getEmails();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getPhones()
	 */
	@Override
	@ElementCollection(fetch = FetchType.LAZY, targetClass = PhoneComponent.class)
	@CollectionTable(name = "PERSONS_PHONES", joinColumns = @JoinColumn(name = ID, nullable = false), uniqueConstraints = @UniqueConstraint(name = "UC_PERSONS_PHONES", columnNames = {
	    "value", ID
	}))
	@IndexColumn(name = "priority", base = 0)
	@ForeignKey(name = "FK_PERSONS_PHONES")
	public List<IPhone> getPhones() {
		return super.getPhones();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getWebSites()
	 */
	@Override
	@ElementCollection(fetch = FetchType.LAZY, targetClass = UriComponent.class)
	@CollectionTable(name = "PERSONS_WEBSITES", joinColumns = @JoinColumn(name = ID, nullable = false), uniqueConstraints = @UniqueConstraint(name = "UC_PERSONS_WEBSITES", columnNames = {
	    "value", ID
	}))
	@IndexColumn(name = "priority", base = 0)
	@ForeignKey(name = "FK_PERSONS_WEBSITES")
	public List<IUri> getWebSites() {
		return super.getWebSites();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getProperties()
	 */
	@Override
	@Transient
	public IGenericPropertiesMap getProperties() {
		return super.getProperties();
	}

	/**
	 * Gets the data.
	 * @return the data
	 */
	@ElementCollection(fetch = FetchType.LAZY, targetClass = GenericPropertyComponent.class)
	@CollectionTable(name = "PERSONS_PROPERTIES", joinColumns = @JoinColumn(name = ID, nullable = false), uniqueConstraints = @UniqueConstraint(name = "UC_PERSONS_PROPERTIES", columnNames = {
	    INamed.NAME, ID
	}))
	@ForeignKey(name = "FK_PERSONS_PROPERTIES")
	protected List<IGenericProperty> getGenericData() {
		return super.getProperties().getData();
	}

	/**
	 * Sets the generic data.
	 * @param values the values
	 */
	protected void setGenericData(final List<IGenericProperty> values) {
		super.getProperties().setData(values);
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getImage()
	 */
	@Override
	@Embedded
	@Target(value = ImageDataComponent.class)
	@AttributeOverrides({
	    @AttributeOverride(name = "type", column = @Column(name = "imageType")),
	    @AttributeOverride(name = "value", column = @Column(name = "imageValue"))
	})
	public IImageData getImage() {
		return super.getImage();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.entities.impl.AbstractEntity#getLocations()
	 */
	@Override
	@ElementCollection(fetch = FetchType.LAZY, targetClass = LocationComponent.class)
	@CollectionTable(name = "PERSONS_LOCATIONS", joinColumns = @JoinColumn(name = ID, nullable = false), uniqueConstraints = @UniqueConstraint(name = "UC_PERSONS_LOCATIONS", columnNames = {
	    ILocation.NAME, ID
	}))
	@IndexColumn(name = "priority", base = 0)
	@ForeignKey(name = "FK_PERSONS_LOCATIONS")
	public List<ILocation> getLocations() {
		return super.getLocations();
	}
}
